home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 7 / Apprentice-Release7.iso / Source Code / Libraries / WASTE 1.3a5 / Demo / Source / WEDemoWindows.c < prev   
Encoding:
C/C++ Source or Header  |  1997-05-11  |  25.8 KB  |  1,111 lines  |  [TEXT/CWIE]

  1. /*
  2.     WASTE Demo Project:
  3.     Window Handling
  4.  
  5.     Copyright © 1993-1997 Marco Piovanelli
  6.     All Rights Reserved
  7.  
  8.     C port by John C. Daub
  9. */
  10.  
  11.  
  12. #ifndef __ALIASES__
  13. #include <Aliases.h>
  14. #endif
  15.  
  16. #ifndef __TOOLUTILS__
  17. #include <ToolUtils.h>
  18. #endif
  19.  
  20. #ifndef __FILETYPESANDCREATORS__
  21. #include <FileTypesAndCreators.h>
  22. #endif
  23.  
  24. #ifndef _LongCoords_
  25. #include "LongCoords.h"
  26. #endif
  27.  
  28. #ifndef __WEDEMOAPP__
  29. #include "WEDemoIntf.h"
  30. #endif
  31.  
  32. #ifndef __SMARTSCROLLAPI__
  33. #include "SmartScroll.h"
  34. #endif
  35.  
  36. // some consts used by DoGrow()
  37.  
  38. enum {
  39.     kMinWindowWidth        = 200,
  40.     kMinWindowHeight    = 80
  41. };
  42.  
  43. // static variables
  44.  
  45. static SInt32 sScrollStep; // how many pixels to scroll (used by ScrollProc)
  46.  
  47.  
  48. static void    CalcGrowIconRect( WindowRef window, Rect *iconRect )
  49. {
  50.     Rect portRect = GetWindowPort( window )->portRect;
  51.  
  52.     iconRect->top = portRect.bottom - (kBarWidth - 2);
  53.     iconRect->left = portRect.right - (kBarWidth - 2);
  54.     iconRect->bottom = portRect.bottom;
  55.     iconRect->right = portRect.right;
  56. }
  57.  
  58. static void    CalcTextRect( WindowRef window, Rect *textRect )
  59. {
  60.     Rect portRect = GetWindowPort( window )->portRect;
  61.  
  62.     textRect->top = 0;
  63.     textRect->left = 0;
  64.     textRect->bottom = portRect.bottom - (kBarWidth - 1);
  65.     textRect->right = portRect.right - (kBarWidth - 1);
  66.     InsetRect( textRect, kTextMargin, kTextMargin );
  67. }
  68.  
  69. static void    CalcScrollBarRect( WindowRef window, VHSelect axis, Rect *barRect )
  70. {
  71.     Rect portRect = GetWindowPort( window )->portRect;
  72.  
  73.     switch ( axis )
  74.     {
  75.         case v:
  76.         {
  77.             barRect->top = -1;
  78.             barRect->left = portRect.right - (kBarWidth - 1);
  79.             barRect->bottom = portRect.bottom - (kBarWidth - 2);
  80.             barRect->right = portRect.right + 1;
  81.             break;
  82.         }
  83.  
  84.         case h:
  85.         {
  86.             barRect->top = portRect.bottom - (kBarWidth - 1);
  87.             barRect->left = -1;
  88.             barRect->bottom = portRect.bottom + 1;
  89.             barRect->right = portRect.right - (kBarWidth - 2 );
  90.             break;
  91.         }
  92.     }
  93. }
  94.  
  95. /*
  96.     the standard Toolbox trap _DrawGrowIcon draws two lines from the grow icon
  97.     to the left and top margins of the window's content area
  98.     these additional lines may create ugly dirt, so we use this routine to temporarily
  99.     set the clip region to the grow icon rect.
  100.  
  101.     in addition, if validate is true, we call _ValidRect on the icon rect
  102. */
  103.  
  104. static void    MyDrawGrowIcon( WindowRef window, Boolean validate )
  105. {
  106.     GrafPtr        savePort;
  107.     RgnHandle    saveClip;
  108.     Rect        r;
  109.  
  110.     // save port and set thePort to wind
  111.  
  112.     GetPort( &savePort );
  113.     SetPortWindowPort( window );
  114.  
  115.     // save the clip region
  116.  
  117.     saveClip = NewRgn();
  118.     GetClip( saveClip );
  119.  
  120.     // calculate the grow icon rect
  121.  
  122.     CalcGrowIconRect( window, &r );
  123.  
  124.     // set clip region to grow icon rect
  125.  
  126.     ClipRect( &r );
  127.  
  128.     // call _DrawGrowIcon
  129.  
  130.     DrawGrowIcon( window );
  131.  
  132.     // if validate is true, remove the grow icon rect from the update region
  133.  
  134.     if ( validate )
  135.         ValidRect( &r );
  136.  
  137.     // restore old clip region
  138.  
  139.     SetClip( saveClip );
  140.     DisposeRgn( saveClip );
  141.  
  142.     // restore old port
  143.  
  144.     SetPort( savePort );
  145. }
  146.  
  147. static void    ScrollBarChanged( WindowRef window )
  148. {
  149.     // scroll text to reflect new scroll bar setting
  150.  
  151.     DocumentHandle hDocument = GetWindowDocument( window );
  152.     WEReference    we;
  153.     LongRect viewRect, destRect;
  154.  
  155.     we = (*hDocument)->we;
  156.     WEGetViewRect( &viewRect, we );
  157.     WEGetDestRect( &destRect, we );
  158.     WEScroll
  159.     (
  160.         viewRect.left - destRect.left - LCGetValue( (*hDocument)->scrollBars[ h ] ),
  161.         viewRect.top - destRect.top - LCGetValue( (*hDocument)->scrollBars[ v ] ),
  162.         we
  163.     );
  164. }
  165.  
  166. static void    AdjustBars ( WindowRef window )
  167. {
  168.     DocumentHandle    hDocument ;
  169.     WEReference        we ;
  170.     GrafPtr            savePort ;
  171.     LongRect        viewRect, destRect ;
  172.     SInt32            visible, total, value, max ;
  173.     ControlRef        bar ;
  174.  
  175.     GetPort ( & savePort ) ;
  176.     SetPortWindowPort ( window ) ;
  177.  
  178.     hDocument = GetWindowDocument ( window ) ;
  179.     we = ( * hDocument ) -> we ;
  180.  
  181.     // get the view and destination rectangle
  182.     WEGetViewRect ( & viewRect, we ) ;
  183.     WEGetDestRect ( & destRect, we ) ;
  184.  
  185.     //    do the vertical axis
  186.  
  187.     //    get scroll bar handle
  188.     bar = ( * hDocument ) -> scrollBars [ v ] ;
  189.  
  190.     //    calculate new scroll bar settings
  191.  
  192.     //    NOTE:  (destRect.bottom - destRect.top) always equals the total text height because
  193.     //    WASTE automatically updates destRect.bottom whenever line breaks are recalculated
  194.  
  195.     total = destRect . bottom - destRect . top ;    //    total pixel height
  196.     visible = viewRect . bottom - viewRect . top ;    //    visible pixel height
  197.     max = total - visible ;                            //    scrollable range (in pixels)
  198.     value = viewRect . top - destRect . top ;        //    thumb location within scrollable range
  199.  
  200.     //    make sure max is always non-negative
  201.     if ( max <= 0 ) max = 0 ;
  202.  
  203.     //    notify SmartScroll
  204.     SetSmartScrollInfo ( bar, visible, total ) ;
  205.  
  206.     //    reset the scroll bar
  207.     LCSetMax ( bar, max ) ;
  208.     LCSetValue ( bar, value ) ;
  209.  
  210.     //    if value exceeds max then the bottom of the destRect is above
  211.     //    the bottom of the view rectangle:  we need to scroll the text downward
  212.     if ( value > max )
  213.     {
  214.         ScrollBarChanged ( window ) ;
  215.     }
  216.  
  217.     //    now do the horizontal axis
  218.  
  219.     //    get scroll bar handle
  220.     bar = ( * hDocument ) -> scrollBars [ h ] ;
  221.  
  222.     //    calculate new scroll bar settings
  223.     total = destRect . right - destRect . left ;    //    total pixel width
  224.     visible = viewRect . right - viewRect . left ;    //    visible pixel width
  225.     max = total - visible ;                            //    scrollable range (in pixels)
  226.     value = viewRect . left - destRect . left ;        //    thumb location within scrollable range
  227.  
  228.     //    make sure max is always non-negative
  229.     if ( max <= 0 ) max = 0 ;
  230.  
  231.     //    notify SmartScroll
  232.     SetSmartScrollInfo ( bar, visible, total ) ;
  233.  
  234.     //    reset the scroll bar
  235.     LCSetMax ( bar, max ) ;
  236.     LCSetValue ( bar, value ) ;
  237.     
  238.     SetPort ( savePort ) ;
  239. }
  240.  
  241. static void    ViewChanged( WindowRef window )
  242. {
  243.     DocumentHandle    hDocument;
  244.     GrafPtr            savePort;
  245.     ControlRef        bar;
  246.     Rect            r;
  247.     LongRect        viewRect;
  248.     VHSelect        axis;
  249.  
  250.     GetPort( &savePort );
  251.     SetPortWindowPort( window );
  252.  
  253.     hDocument = GetWindowDocument( window );
  254.  
  255.     //    resize the text area
  256.  
  257.     CalcTextRect( window, &r );
  258.     WERectToLongRect( &r, &viewRect );
  259.     WESetViewRect( &viewRect, (*hDocument)->we );
  260.  
  261.     //     move and resize the control bars
  262.  
  263.     for ( axis = v; axis <= h; axis++ )
  264.     {
  265.         bar = (*hDocument)->scrollBars[ axis ];
  266.         CalcScrollBarRect( window, axis, &r );
  267.         MoveControl( bar, r.left, r.top );
  268.         SizeControl( bar, r.right - r.left, r.bottom - r.top );
  269.         ValidRect( &r );
  270.     }
  271.  
  272.     //    reset the thumb positions and the max values of the control bars
  273.     AdjustBars( window );
  274.  
  275.     //    redraw the control bars
  276.  
  277.     ShowControl( (*hDocument)->scrollBars[ v ] );
  278.     ShowControl( (*hDocument)->scrollBars[ h ] );
  279.  
  280.     SetPort( savePort );
  281. }
  282.  
  283. /*
  284.     This is a deviation from the original Pascal WASTE Demo App code.
  285.  
  286.     This "morally correct" code for window dragging is per an article in MacTech
  287.     Magazine (July 1994, Vol 10, No. 7). by Eric Shapiro (of Rock Ridge Enterprises)
  288.     called "Multiple Monitors vs. Your Application"
  289.  
  290.     Eric addressed numerous things to allow your app to deal nicely with multiple
  291.     monitor setups, one of them is dragging.
  292.  
  293.     According to Eric, many apps don't let you drag windows to second monitors, and
  294.     though holding down the cmd/opt keys often overrides this problem, it should
  295.     still be updated.  And the only reason qd.screenBits.bounds works to allow
  296.     you to drag to second monitors is because of a kludge Apple put in the Window Manager
  297.  
  298.     So, this is some code from Eric to make our app be "morally correct" :)
  299. */
  300.  
  301. void DoDrag ( Point thePoint, WindowRef window )
  302. {
  303.     Rect desktopBounds ;
  304.  
  305.     if ( gHasColorQD )
  306.     {
  307.         desktopBounds = ( * GetGrayRgn ( ) ) -> rgnBBox ;
  308.     }
  309.     else
  310.     {
  311.         desktopBounds = qd . screenBits . bounds ;
  312.     }
  313.  
  314.     DragWindow ( window, thePoint, & desktopBounds ) ;
  315. }
  316.  
  317. void Resize ( Point newSize, WindowRef window )
  318. {
  319.     DocumentHandle    hDocument ;
  320.     GrafPtr            savePort ;
  321.     Rect            r ;
  322.     RgnHandle        tempRgn, dirtyRgn ;
  323.  
  324.     //    set up the port
  325.     GetPort( & savePort ) ;
  326.     SetPortWindowPort ( window ) ;
  327.  
  328.     hDocument = GetWindowDocument ( window ) ;
  329.  
  330.     //    create temporary regions for calculations
  331.     tempRgn = NewRgn ( ) ;
  332.     dirtyRgn = NewRgn ( ) ;
  333.  
  334.     //    save old text region
  335.     CalcTextRect ( window, & r ) ;
  336.     RectRgn ( tempRgn, & r ) ;
  337.  
  338.     //    erase the old grow icon rect
  339.     CalcGrowIconRect ( window, & r ) ;
  340.     EraseRect ( & r ) ;
  341.  
  342.     //    hide the scroll bars
  343.     HideControl ( ( * hDocument ) -> scrollBars [ v ] ) ;
  344.     HideControl ( ( * hDocument ) -> scrollBars [ h ] ) ;
  345.  
  346.     //    perform the actual resizing of the window, redraw scroll bars and grow icon
  347.     SizeWindow ( window, newSize . h, newSize . v, false ) ;
  348.     ViewChanged ( window ) ;
  349.     MyDrawGrowIcon ( window, true ) ;
  350.  
  351.     //    calculate the dirty region (to be updated)
  352.     CalcTextRect ( window, & r );
  353.     RectRgn ( dirtyRgn, & r ) ;
  354.     XorRgn ( dirtyRgn, tempRgn, dirtyRgn ) ;
  355.     InsetRect ( & r, - kTextMargin, - kTextMargin ) ;
  356.     RectRgn ( tempRgn, & r ) ;
  357.     SectRgn ( dirtyRgn, tempRgn, dirtyRgn ) ;
  358.  
  359.     //    mark the dirty region as invalid
  360.     InvalRgn ( dirtyRgn ) ;
  361.  
  362.     //    throw away temporary regions
  363.     DisposeRgn ( tempRgn ) ;
  364.     DisposeRgn ( dirtyRgn ) ;
  365.  
  366.     //    restore the port
  367.     SetPort ( savePort ) ;
  368. }
  369.  
  370. void DoGrow ( Point hitPt, WindowRef window )
  371. {
  372.     Rect sizeRect ;
  373.     SInt32 newSize ;
  374.  
  375.     SetRect( & sizeRect, kMinWindowWidth, kMinWindowHeight, SHRT_MAX, SHRT_MAX ) ;
  376.     if ( ( newSize = GrowWindow ( window, hitPt, & sizeRect ) ) != 0L )
  377.     {
  378.         //    for some reason, GrowWindow( ) returns a long value,
  379.         //    but it's really a Point
  380.  
  381.         Resize ( * ( Point * ) & newSize, window ) ;
  382.     }
  383. }
  384.  
  385. void DoZoom ( SInt16 partCode, WindowRef window )
  386. {
  387.     DocumentHandle    hDocument;
  388.     GrafPtr            savePort;
  389.     Rect            r;
  390.  
  391.     GetPort( &savePort );
  392.     SetPortWindowPort( window );
  393.  
  394.     hDocument = GetWindowDocument(window);
  395.  
  396.     r = GetWindowPort( window )->portRect;
  397.     EraseRect( &r );
  398.     HideControl( (*hDocument)->scrollBars[ v ] );
  399.     HideControl( (*hDocument)->scrollBars[ h ] );
  400.  
  401.     ZoomWindow( window, partCode, false );
  402.  
  403.     ViewChanged( window );
  404.     CalcTextRect( window, &r );
  405.     InvalRect( &r );
  406.  
  407.     SetPort( savePort );
  408. }
  409.  
  410. // this is a callback tourine called by the Toolbox Control Manager
  411. // move the scroll bar thumb and scroll the text accordingly
  412.  
  413. static pascal void ScrollProc ( ControlRef bar, ControlPartCode partCode )
  414. {
  415.     SInt32 value, step ;
  416.  
  417.     if ( partCode == kControlNoPart )
  418.     {
  419.         return ;
  420.     }
  421.  
  422.     value = LCGetValue ( bar ) ;
  423.     step = sScrollStep ;
  424.  
  425.     if ( ( ( value < LCGetMax ( bar ) ) && ( step > 0 ) ) ||
  426.          ( ( value > 0 ) && ( step < 0 ) ) )
  427.     {
  428.         LCSetValue ( bar, value + step ) ;
  429.         ScrollBarChanged ( FrontWindow ( ) ) ;
  430.     }
  431. }
  432.  
  433. static SInt32 SendControlMessage ( ControlRef inControl, SInt16 inMessage, SInt32 inParam )
  434. {
  435.     GrafPtr savePort ;
  436.     Handle cdef ;
  437.     SInt32 result ;
  438.     SInt8 saveState ;
  439.  
  440.     //    get a handle to the control definition procedure
  441.     cdef = ( * inControl ) -> contrlDefProc ;
  442.     
  443.     //    make sure the CDEF is loaded
  444.     if ( * cdef == nil )
  445.     {
  446.         LoadResource ( cdef ) ;
  447.         if ( * cdef == nil )
  448.         {
  449.             return 0 ;        //    emergency exit (couldn't load CDEF)
  450.         }
  451.     }
  452.  
  453.     //    lock it down
  454.     saveState = HGetState ( cdef ) ;
  455.     HLock ( cdef ) ;
  456.  
  457.     //    set up the port
  458.     GetPort ( & savePort ) ;
  459.     SetPortWindowPort ( ( * inControl ) -> contrlOwner ) ;
  460.  
  461.     //    call the CDEF
  462.     result = CallControlDefProc ( ( ControlDefUPP ) StripAddress ( * cdef ),
  463.                 GetControlVariant ( inControl ), inControl, inMessage, inParam ) ;
  464.     
  465.     //    unlock the CDEF
  466.     HSetState ( cdef, saveState ) ;
  467.  
  468.     //    restore the port
  469.     SetPort ( savePort ) ;
  470.     
  471.     //    return result code
  472.     return result ;
  473. }
  474.  
  475. static void LiveScroll ( ControlRef inControl, Point inHitPt, WindowRef inWindow )
  476. {
  477.     IndicatorDragConstraint constraint ;
  478.     Point mouseLoc ;
  479.     SInt32 initialValue, oldValue, curValue, max ;
  480.     SInt16 scrollRange, delta ;
  481.     VHSelect orientation ;
  482.     
  483.     //    hilite the control thumb
  484.     //    this does nothing with the standard System 7.x scroll bar, but is required for
  485.     //    correct visual feedback with the Apple Grayscale Appearance (as implemented by
  486.     //    the Appearance control panel in MacOS 8, or by Aaron/Kaleidoscope)
  487.     HiliteControl ( inControl, kControlIndicatorPart ) ;
  488.  
  489.     //    get limit & slop rects that should be used for dragging the indicator
  490.     //    (see IM: Mac Toolbox Essentials, page 5-114)
  491.     * ( Point * ) & constraint . limitRect = inHitPt ;
  492.     SendControlMessage ( inControl, thumbCntl, ( SInt32 ) & constraint ) ;
  493.     
  494.     //    determine the orientation of the scroll bar
  495.     orientation = ( constraint . axis == kVerticalConstraint ) ? h : v ;
  496.  
  497.     //    calculate the area in which the thumb can travel
  498.     if ( orientation == v )
  499.     {
  500.         scrollRange = ( constraint . limitRect . bottom - constraint . limitRect . top ) ;
  501.     }
  502.     else
  503.     {
  504.         scrollRange = ( constraint . limitRect . right - constraint . limitRect . left ) ;
  505.     }
  506.     
  507.     //    get current value & max
  508.     initialValue = oldValue = curValue = LCGetValue ( inControl ) ;
  509.     max = LCGetMax ( inControl ) ;
  510.     
  511.     //    mouse tracking loop
  512.     while ( StillDown ( ) )
  513.     {
  514.         //    get current mouse location
  515.         GetMouse ( & mouseLoc ) ;
  516.  
  517.         //    do nothing if the mouse is outside the slop rectangle
  518.         if ( PtInRect ( mouseLoc, & constraint . slopRect ) )
  519.         {
  520.             //    calculate pixel offset relative to initial hit point
  521.             if ( orientation == v )
  522.             {
  523.                 delta = mouseLoc . v - inHitPt . v ;
  524.             }
  525.             else
  526.             {
  527.                 delta = mouseLoc . h - inHitPt . h ;
  528.             }
  529.             
  530.             //    calculate new control value
  531.             curValue = initialValue + FixMul ( max, FixRatio ( delta, scrollRange ) ) ;
  532.             if ( curValue < 0 ) curValue = 0 ;
  533.             if ( curValue > max ) curValue = max ;    
  534.         }
  535.  
  536.         if ( curValue != oldValue )
  537.         {
  538.             //    set new control value
  539.             LCSetValue ( inControl, curValue ) ;
  540.             ScrollBarChanged ( inWindow ) ;
  541.             oldValue = curValue ;
  542.         }
  543.     }
  544.     
  545.     //    unhighlight the thumb
  546.     HiliteControl ( inControl, kControlNoPart ) ;
  547. }
  548.  
  549. static void    DoScrollBar ( Point hitPt, EventModifiers modifiers, WindowRef window )
  550. {
  551.     DocumentHandle        hDocument;
  552.     ControlRef            bar = nil;
  553.     LongRect            viewRect;
  554.     ControlPartCode        partCode;
  555.     SInt32                pageSize;
  556.     SInt32                step = 0;
  557.  
  558. #ifdef __cplusplus
  559.     static ControlActionUPP sScrollerUPP = NewControlActionProc( ScrollProc );
  560. #else
  561.     static ControlActionUPP sScrollerUPP = nil;
  562.     if (sScrollerUPP == nil)
  563.     {
  564.         sScrollerUPP = NewControlActionProc( ScrollProc );
  565.     }
  566. #endif
  567.  
  568.     hDocument = GetWindowDocument( window );
  569.     WEGetViewRect( &viewRect, (*hDocument)->we );
  570.  
  571.     //    find out which control was hit (if any) and in which part
  572.     partCode = FindControl( hitPt, window, &bar );
  573.  
  574.     //    if any control was hit, it must be one of our two scroll bars:
  575.     //    find out which and calculate the page size for it
  576.     if ( bar == (*hDocument)->scrollBars[ v ] )
  577.     {
  578.         pageSize = viewRect.bottom - viewRect.top;
  579.     }
  580.     else if ( bar == (*hDocument)->scrollBars[ h ] )
  581.     {
  582.         pageSize = viewRect.right - viewRect.left;
  583.     }
  584.     else
  585.     {
  586.         return;        // return immediately if none of our scrollbars was hit
  587.     }
  588.  
  589.     //    dispatch on partCode
  590.     switch ( partCode )
  591.     {
  592.         case kControlIndicatorPart:
  593.         {
  594.             // click in thumb
  595.             if ( modifiers & optionKey )
  596.             {
  597.                 // call TrackControl with no actionProc and adjust text
  598.                 TrackControl ( bar, hitPt, nil ) ;
  599.                 LCSynch ( bar ) ;
  600.                 ScrollBarChanged ( window ) ;
  601.             }
  602.             else
  603.             {
  604.                 LiveScroll ( bar, hitPt, window ) ;
  605.             }
  606.             return;
  607.         }
  608.  
  609.         case kControlUpButtonPart:
  610.         {
  611.             step = - ( ( modifiers & optionKey ) ? 1 : kScrollDelta ) ;
  612.             break ;
  613.         }
  614.  
  615.         case kControlDownButtonPart:
  616.         {
  617.             step = + ( ( modifiers & optionKey ) ? 1 : kScrollDelta ) ;
  618.             break ;
  619.         }
  620.  
  621.         case kControlPageUpPart:
  622.         {
  623.             step = - ( pageSize - kScrollDelta ) ;
  624.             break ;
  625.         }
  626.  
  627.         case kControlPageDownPart:
  628.         {
  629.             step = + ( pageSize - kScrollDelta ) ;
  630.             break ;
  631.         }
  632.  
  633.     }    // switch
  634.  
  635.     //    save step in a static variable for our ScrollProc callback
  636.     sScrollStep = step ;
  637.  
  638.     //    track the mouse
  639.     TrackControl ( bar, hitPt, sScrollerUPP ) ;
  640. }
  641.  
  642. /*
  643.     This is a callback routine called whenever the text is scrolled automaticall.
  644.     Since auto-scrolling is enabled, WEScroll may be invoked internally by WASTE
  645.     in many different circumstances, and we want to be notified when this happens
  646.     so we can adjust the scroll bars
  647. */
  648.  
  649. static pascal void TextScrolled ( WEReference we )
  650. {
  651.     WindowRef window = nil ;
  652.  
  653.     //    retrieve the window pointer stored in the WE instance as a "reference constant"
  654.     if ( WEGetInfo( weRefCon, & window, we ) != noErr )
  655.     {
  656.         return ;
  657.     }
  658.  
  659.     //    make sure the scroll bars are in synch with the destination rectangle
  660.     AdjustBars ( window ) ;
  661. }
  662.  
  663. Boolean    DoContent ( Point hitPt, const EventRecord * event, WindowRef window )
  664. {
  665.     WEReference        we = GetWindowWE ( window ) ;
  666.     Rect            textRect ;
  667.     GrafPtr            savePort ;
  668.     Boolean            isMyClick = false ;
  669.  
  670.     //    set up the port
  671.     GetPort ( & savePort ) ;
  672.     SetPortWindowPort ( window ) ;
  673.  
  674.     //    convert the point to local coordinates
  675.     GlobalToLocal ( & hitPt ) ;
  676.  
  677.     //    a click in an inactive window should normally activate it,
  678.     //    but the availability of the Drag Manager introduces an exception to this rule:
  679.     //    a click in the background selection may start a drag gesture,
  680.     //    without activating the window
  681.  
  682.     if ( IsWindowHilited ( window ) )
  683.     {
  684.         isMyClick = true ;            //    active window -> always handle click
  685.     }
  686.     else if ( gHasDragAndDrop )
  687.     {
  688.         SInt32 selStart, selEnd ;
  689.         RgnHandle selRgn ;
  690.  
  691.         WEGetSelection ( & selStart, & selEnd, we ) ;
  692.         selRgn = WEGetHiliteRgn ( selStart, selEnd, we ) ;
  693.         isMyClick = PtInRgn ( hitPt, selRgn ) && WaitMouseMoved ( event -> where ) ;
  694.         DisposeRgn ( selRgn ) ;
  695.     }
  696.  
  697.     if ( isMyClick )
  698.     {
  699.         CalcTextRect ( window, & textRect ) ;
  700.  
  701.         if ( PtInRect ( hitPt, & textRect ) )
  702.         {
  703.             WEClick ( hitPt, event -> modifiers, event -> when, we ) ;
  704.         }
  705.         else
  706.         {
  707.             DoScrollBar ( hitPt, event -> modifiers, window ) ;
  708.         }
  709.     }
  710.  
  711.     //    restore the port
  712.     SetPort ( savePort ) ;
  713.  
  714.     //    return true if the click should activate this window
  715.     return ! isMyClick ;
  716. }
  717.  
  718. static void    DoScrollKey ( SInt16 keyCode, WindowRef window )
  719. {
  720.     DocumentHandle        hDocument ;
  721.     ControlRef            bar ;
  722.     SInt32                value ;
  723.     LongRect            viewRect ;
  724.  
  725.     hDocument = GetWindowDocument ( window ) ;
  726.     bar = ( * hDocument ) -> scrollBars [ v ] ;
  727.  
  728.     //    get current scroll bar value
  729.     value = LCGetValue ( bar ) ;
  730.  
  731.     //    get text view rect
  732.     WEGetViewRect ( & viewRect, ( * hDocument ) -> we ) ;
  733.  
  734.     switch ( keyCode )
  735.     {
  736.  
  737.         case keyPgUp:
  738.         {
  739.             value -= ( viewRect . bottom - viewRect . top ) - kScrollDelta ;
  740.             break ;
  741.         }
  742.  
  743.         case keyPgDn:
  744.         {
  745.             value += ( viewRect . bottom - viewRect . top ) - kScrollDelta ;
  746.             break ;
  747.         }
  748.  
  749.         case keyHome:
  750.         {
  751.             value = 0 ;
  752.             break ;
  753.         }
  754.  
  755.         case keyEnd:
  756.         {
  757.             value = LONG_MAX ;
  758.             break ;
  759.         }
  760.     }    // switch
  761.  
  762.     //    set the new scroll bar value and scroll the text pane accordingly
  763.  
  764.     LCSetValue ( bar, value ) ;
  765.     ScrollBarChanged ( window ) ;
  766. }
  767.  
  768. void DoKey ( SInt16 key, const EventRecord * event )
  769. {
  770.     WindowRef window ;
  771.     SInt16 keyCode ;
  772.  
  773.     //    do nothing if no window is active
  774.     if ( ( window = FrontWindow ( ) ) == nil )
  775.         return;
  776.  
  777.     //    extract virtual key code from event record
  778.     keyCode = ( event->message & keyCodeMask ) >> 8 ;
  779.  
  780.     // page movement keys are handled by DoScrollKey()
  781.     switch ( keyCode )
  782.     {
  783.         case keyPgUp:
  784.         case keyPgDn:
  785.         case keyHome:
  786.         case keyEnd:
  787.         {
  788.             DoScrollKey ( keyCode, window ) ;
  789.             break ;
  790.         }
  791.  
  792.         default:
  793.         {
  794.             WEKey ( key, event -> modifiers, GetWindowWE (window) ) ;
  795.             break ;
  796.         }
  797.     }
  798. }
  799.  
  800. void DoUpdate ( WindowRef window )
  801. {
  802.     GrafPtr        savePort ;
  803.     RgnHandle    updateRgn ;
  804.  
  805.     // if we have no windows, there's nothing to update!
  806.     if ( window == nil )
  807.     {
  808.         return ;
  809.     }
  810.  
  811.     // save the old drawing port
  812.     GetPort ( & savePort ) ;
  813.     SetPortWindowPort ( window ) ;
  814.  
  815.     // notify everything that we're doing an update.
  816.     BeginUpdate ( window ) ;
  817.  
  818.     // BeginUpdate sets the window port visRgn to the region to update
  819.     updateRgn = GetWindowPort ( window ) -> visRgn ;
  820.  
  821.     if ( ! EmptyRgn ( updateRgn ) )    // if it's not an empty region, let's update it!
  822.     {
  823.         // erase the update region
  824.         EraseRgn ( updateRgn ) ;
  825.  
  826.         //    draw scroll bars
  827.         UpdateControls ( window, updateRgn ) ;
  828.  
  829.         //    draw grow icon
  830.         MyDrawGrowIcon ( window, false ) ;
  831.  
  832.         //    draw text
  833.         WEUpdate ( updateRgn, GetWindowWE ( window ) ) ;
  834.     }
  835.  
  836.     // tell everything we're done updating
  837.     EndUpdate ( window ) ;
  838.  
  839.     // restore the old graphics port
  840.     SetPort ( savePort ) ;
  841. }
  842.  
  843. void DoActivate ( Boolean isActivating, WindowRef window )
  844. {
  845.     DocumentHandle        hDocument ;
  846.     WEReference            we ;
  847.     GrafPtr                savePort ;
  848.     Rect                barRect ;
  849.     ControlPartCode        barHilite ;
  850.     SInt16                menuID ;
  851.     VHSelect            axis ;
  852.  
  853.     // if this is not one of our document windows, nothing to do here...
  854.     if ( ( hDocument = GetWindowDocument ( window ) ) == nil )
  855.     {
  856.         return ;
  857.     }
  858.     we = ( * hDocument ) -> we ;
  859.  
  860.     //    sanity check: do nothing if required activation state
  861.     //    is the same as the current activation state
  862.     if ( isActivating == WEIsActive ( we ) )
  863.     {
  864.         return ;
  865.     }
  866.  
  867.     //     set up the port
  868.     GetPort ( & savePort ) ;
  869.     SetPortWindowPort ( window ) ;
  870.  
  871.     // activate or deactivate the text (and any other relevant stuff) depending on just
  872.     // what we're doing here...
  873.     if ( isActivating )
  874.     {
  875.         WEActivate ( we ) ;
  876.         barHilite = kControlNoPart ;
  877.     }
  878.     else
  879.     {
  880.         WEDeactivate ( we ) ;
  881.         barHilite = kControlDisabledPart ;
  882.     }
  883.  
  884.     //    redraw the grow icon (and validate its rect)
  885.     MyDrawGrowIcon ( window, true ) ;
  886.  
  887.     //    redraw the scroll bars with the new highlighting (and validate their rects)
  888.     for ( axis = v ; axis <= h ; axis ++ )
  889.     {
  890.         HiliteControl ( ( * hDocument ) -> scrollBars [ axis ], barHilite ) ;
  891.         CalcScrollBarRect ( window, axis, & barRect ) ;
  892.         ValidRect ( & barRect ) ;
  893.     }
  894.  
  895.     //    if activating, undim text-related menus
  896.     if ( isActivating )
  897.     {
  898.         for ( menuID = kMenuEdit ; menuID <= kMenuFeatures ; menuID ++ )
  899.         {
  900.             EnableItem ( GetMenuHandle ( menuID ), 0 ) ;
  901.         }
  902.     }
  903.  
  904.     // invalidate the menu bar
  905.     InvalMenuBar ( ) ;
  906.  
  907.     // restore the old graphics port..
  908.     SetPort ( savePort ) ;
  909. }
  910.  
  911. OSErr CreateWindow ( const FSSpec * pFileSpec )
  912. {
  913.     DocumentHandle    hDocument = nil ;
  914.     WindowRef        window = nil ;
  915.     AliasHandle        alias = nil ;
  916.     WEReference        we = nil ;
  917.     ControlRef        bar = nil ;
  918.     FInfo            fileInfo ;
  919.     Rect            textRect ;
  920.     LongRect        lr ;
  921.     VHSelect        axis ;
  922.     OSErr            err ;
  923.  
  924. #ifdef __cplusplus
  925.     static WEScrollUPP sScrollerUPP = NewWEScrollProc ( TextScrolled ) ;
  926. #else
  927.     static WEScrollUPP sScrollerUPP = nil ;
  928.     if ( sScrollerUPP == nil )
  929.     {
  930.         sScrollerUPP = NewWEScrollProc ( TextScrolled ) ;
  931.     }
  932. #endif
  933.  
  934.     //    allocate a relocateable block to hold a document record
  935.     hDocument = ( DocumentHandle ) NewHandleClear ( sizeof ( DocumentRecord ) ) ;
  936.     if ( ( err = MemError( ) ) != noErr )
  937.     {
  938.         goto cleanup ;
  939.     }
  940.  
  941.     //    create the window from a 'WIND' template: the window is initially invisible
  942.     //    if ColorQuickDraw is available, create a color window
  943.     if ( gHasColorQD )
  944.     {
  945.         window = GetNewCWindow ( kWindowTemplateID, nil, ( WindowRef ) -1L ) ;
  946.     }
  947.     else
  948.     {
  949.         window = GetNewWindow ( kWindowTemplateID, nil, ( WindowRef ) -1L ) ;
  950.     }
  951.  
  952.     //    make sure we got a window
  953.     if ( window == nil )
  954.     {
  955.         err = memFullErr ;
  956.         goto cleanup ;
  957.     }
  958.  
  959.     // link the document record to the window and the other way around
  960.     SetWRefCon ( window, ( SInt32 ) hDocument ) ;
  961.     ( * hDocument ) -> owner = window ;
  962.  
  963.     // we got a window, so tell QuickDraw where to draw...
  964.     SetPortWindowPort ( window ) ;
  965.  
  966.     //    calculate the text rectangle
  967.     CalcTextRect ( window, & textRect ) ;
  968.     WERectToLongRect ( & textRect, & lr ) ;
  969.  
  970.     //    create a new WASTE instance
  971.     if ( ( err = WENew ( & lr, & lr, weDoAutoScroll +
  972.                                      weDoOutlineHilite +
  973.                                      weDoUndo +
  974.                                      weDoIntCutAndPaste +
  975.                                      weDoDragAndDrop +
  976.                                      weDoUseTempMem +
  977.                                      weDoDrawOffscreen, & we) ) != noErr )
  978.     {
  979.         goto cleanup ;
  980.     }
  981.  
  982.     //    save a reference to the window in the WE instance
  983.     if ( ( err = WESetInfo ( weRefCon, & window, we ) ) != noErr )
  984.     {
  985.         goto cleanup ;
  986.     }
  987.  
  988.     //    now the other way around:  save the WE reference in the document record
  989.     ( * hDocument ) -> we = we ;
  990.  
  991.     //    set up our scroll callback
  992.     if ( ( err = WESetInfo ( weScrollProc, & sScrollerUPP, we ) ) != noErr )
  993.     {
  994.         goto cleanup ;
  995.     }
  996.  
  997.     //    create the scroll bars from a control template
  998.     for ( axis = v ; axis <= h; axis ++ )
  999.     {
  1000.         if ( ( bar = GetNewControl ( kScrollBarTemplateID, window ) ) == nil )
  1001.         {
  1002.             err = memFullErr ;
  1003.             goto cleanup ;
  1004.         }
  1005.         HiliteControl ( bar, kControlDisabledPart ) ;
  1006.  
  1007.         //    attach a LongControl record to the scroll bar:  this allows us to use long
  1008.         //    settings and thus scroll text taller than 32,767 pixels
  1009.         if ( ( err = LCAttach ( bar ) ) != noErr )
  1010.         {
  1011.             goto cleanup;
  1012.         }
  1013.  
  1014.         //    save control handle in the document record
  1015.         ( * hDocument ) -> scrollBars [ axis ] = bar ;
  1016.  
  1017.     }    // for
  1018.  
  1019.     //    ViewChanged adjusts the scroll bars rectangles to the window frame
  1020.     ViewChanged ( window ) ;
  1021.  
  1022.     //    if pFileSpec is not nil, it points to a file to read, so let's read it!
  1023.     if ( pFileSpec != nil )
  1024.     {
  1025.         // turn the cursor into a wristwatch because this can be a lengthy operation
  1026.         SetCursor ( * GetCursor ( watchCursor ) ) ;
  1027.  
  1028.         //    retrieve file infomation
  1029.         if ( ( err = FSpGetFInfo ( pFileSpec, & fileInfo ) ) != noErr )
  1030.         {
  1031.             goto cleanup ;
  1032.         }
  1033.  
  1034.         //    make sure we recognize the file type
  1035.         if ( ( fileInfo . fdType != kTypeText ) && ( fileInfo . fdType != ftSimpleTextDocument ) )
  1036.         {
  1037.             err = badFileFormat ;
  1038.             goto cleanup ;
  1039.         }
  1040.  
  1041.         //    read in the file
  1042.         if ( ( err = ReadTextFile ( pFileSpec, we ) ) != noErr )
  1043.         {
  1044.             goto cleanup ;
  1045.         }
  1046.  
  1047.         //    set the window title to the file name
  1048.         SetWTitle ( window, pFileSpec -> name ) ;
  1049.  
  1050.         //    create an alias to keep track of the file
  1051.         if ( ( err = NewAlias ( nil, pFileSpec, & alias ) ) != noErr )
  1052.         {
  1053.             goto cleanup ;
  1054.         }
  1055.         ( * hDocument ) -> fileAlias = ( Handle ) alias ;
  1056.  
  1057.         //    if the file is a read-only file, go ahead and enable those flags
  1058.         if ( fileInfo . fdType == ftSimpleTextDocument )
  1059.         {
  1060.             WEFeatureFlag ( weFReadOnly, weBitSet, we ) ;
  1061.         }
  1062.  
  1063.         //    let's make sure the cursor is happy...
  1064.         SetCursor ( & qd . arrow ) ;
  1065.     }
  1066.  
  1067.     //    adjust scroll bar settings based on the total text height
  1068.     AdjustBars ( window ) ;
  1069.  
  1070.     //    finally!  show the document window
  1071.     ShowWindow ( window ) ;
  1072.  
  1073. cleanup:
  1074.     if ( err != noErr )
  1075.     {
  1076.         ErrorAlert ( err ) ;
  1077.     }
  1078.     return err ;
  1079. }
  1080.  
  1081. void DestroyWindow ( WindowRef window )
  1082. {
  1083.     DocumentHandle    hDocument ;
  1084.     SInt16            menuID ;
  1085.  
  1086.     hDocument = GetWindowDocument ( window ) ;
  1087.  
  1088.     //    destroy the WASTE instance
  1089.     WEDispose ( ( * hDocument ) -> we ) ;
  1090.  
  1091.     //    destory the LongControl records attached to the scroll bars
  1092.     LCDetach ( ( * hDocument ) -> scrollBars [ v ] ) ;
  1093.     LCDetach ( ( * hDocument ) -> scrollBars [ h ] ) ;
  1094.  
  1095.     //    dispose of the file alias, if any
  1096.     ForgetHandle ( & ( ( * hDocument ) -> fileAlias ) ) ;
  1097.  
  1098.     //    destroy the window record and all associated data structures
  1099.     DisposeWindow ( window ) ;
  1100.  
  1101.     //    finally, dispose of the document record
  1102.     DisposeHandle ( ( Handle ) hDocument ) ;
  1103.  
  1104.     // adjust the menus to suit
  1105.     for ( menuID = kMenuFont ; menuID <= kMenuFeatures ; menuID ++ )
  1106.     {
  1107.         DisableItem ( GetMenuHandle ( menuID ), 0 ) ;
  1108.     }
  1109.     InvalMenuBar ( ) ;
  1110. }
  1111.